package org.smarthings.things.automation.rest.impl;

import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.smarthings.things.automation.Rule;
import org.smarthings.things.automation.RuleCollection;
import org.smarthings.things.automation.RuleEngine;
import org.smarthings.things.automation.rest.RemoteRulesManagement;
import org.smarthings.things.automation.rest.resources.RuleColleactionResource;
import org.smarthings.things.automation.rest.resources.RuleResource;
import org.smarthings.things.automation.util.ActionFactory;
import org.smarthings.things.automation.util.ConditionFactory;
import org.smarthings.things.automation.util.TriggerFactory;
import org.smarthings.things.commons.rest.VersionResource;
import org.smarthings.things.commons.utils.QueryParametersUtils;

@Path("rules")
@Component(immediate = true)
@Service(RemoteRulesManagement.class)
public class RemoteRulesManagementImpl implements RemoteRulesManagement {

	@Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.MANDATORY_UNARY)
	private RuleEngine ruleRegistry;

	@Context
	private HttpHeaders headers;

	@Context
	private UriInfo uri;

	public void bindRuleRegistry(RuleEngine ruleRegistry) {
		this.ruleRegistry = ruleRegistry;
	}

	public void unbindRuleRegistry(RuleEngine ruleRegistry) {
		this.ruleRegistry = null;
	}

	public VersionResource getVersion() throws WebApplicationException {
		return RulesResourceFactory.getVersion(uri);
	}

	public Response registerRule(RuleResource rule) throws WebApplicationException {
		try {
			Rule registered = ruleRegistry.registerRule(rule.getName(), rule.getTags(),
					TriggerFactory.getTrigger(rule.getTrigger().getExpression()), ConditionFactory
							.getCondition(rule.getCondition().getLanguage(), rule.getCondition()
									.getScript()), ActionFactory.getAction(rule.getAction()
							.getLanguage(), rule.getAction().getScript()));
			RuleResource created = RulesResourceFactory.getRule(registered, uri);
			return Response.created(created.getHref()).entity(created).build();
		} catch (RuntimeException e) {
			throw new WebApplicationException(e);
		}
	}
	
	@Override
	public RuleResource updateRule(String ruleUUID, RuleResource updated) throws WebApplicationException {
		Rule rule = validateRuleUUID(ruleUUID);
		rule.setActiveSate(updated.isActive());
//		rule.setAction(ActionFactory.getAction(updated.getAction(), script));TODO
		return RulesResourceFactory.getRule(ruleRegistry.getRule(ruleUUID), uri);
	}

	public Response unregisterRule(String ruleUUID) throws WebApplicationException {
		validateRuleUUID(ruleUUID);
		ruleRegistry.unregisterRule(ruleUUID);
		return Response.ok().build();
	}

	public RuleColleactionResource getRules(String filter) throws WebApplicationException {
		try {
			int offset = QueryParametersUtils.getOffset(uri);
			int limit = QueryParametersUtils.getLimit(uri);

			RuleCollection collection = filter != null ? ruleRegistry.filterRules(filter)
					: ruleRegistry.listRules();
			return RulesResourceFactory.getRuleColleactionResource(
					collection.paginator(offset, limit).first(), offset, limit, uri);
		} catch (RuntimeException e) {
			throw new WebApplicationException(e);
		}
	}

	public RuleResource getRule(String ruleUUID) throws WebApplicationException {
		validateRuleUUID(ruleUUID);
		return RulesResourceFactory.getRule(ruleRegistry.getRule(ruleUUID), uri);
	}

	private Rule validateRuleUUID(String ruleUUID) throws IllegalArgumentException {
		Rule rule = ruleRegistry.getRule(ruleUUID);
		if (rule == null) {
			throw new IllegalArgumentException("No rule with UUID " + ruleUUID);
		}
		return rule;
	}

}
